import socketRegApi from '@/api/socket/socketRegApi'
import { getAppNav } from '@/App'
import LocalStorageKey from '@/constant/LocalStorageKey'
import SessionStorageKey from '@/constant/SessionStorageKey'
import ISocketMessage from '@/model/other/ISocketMessage'
import { ToastError } from './CommonUtil'
import { logout } from './UserUtil'

let socketUrl = ''
let code = ''
let socket: WebSocket | null = null
let heartbeat: NodeJS.Timer

function getSocketUrl() {
  socketUrl = ''
  code = ''
  return socketRegApi()
    .then(({ data }) => {
      socketUrl = data.data.socketUrl
      code = data.data.code
    })
    .catch(async () => {
      if (!localStorage.getItem(LocalStorageKey.JWT)) {
        return // 如果没有 jwt，则不重连了，目的：防止一直连
      }
      await new Promise((resolve) => {
        setTimeout(async () => {
          await getSocketUrl() // 等 2秒，再次获取 socket服务器
          resolve(null)
        }, 2000)
      })
    })
}

// 关闭 socket
export function closeSocket() {
  if (socket) {
    socket.close()
    socket = null
  }
}

// 先判断是否有socket服务，如果有才去连接
export function connectionSocket(
  doSetSocketMessage: (params: ISocketMessage) => void,
  doSetSocketStatus: (params: boolean) => void
) {
  if (socket) {
    return
  }
  if (!localStorage.getItem(LocalStorageKey.JWT)) {
    return // 如果没有 jwt，则不重连了，目的：防止一直连
  }
  return new Promise(async (resolve, reject) => {
    if (window.WebSocket) {
      if (!socket) {
        await getSocketUrl()
        if (!socketUrl || !code) {
          return reject(new Error('连接 socket失败：暂无可用的服务器'))
        }
        socket = new WebSocket(
          `${
            import.meta.env.DEV ? 'ws:' : 'wss:'
          }//${socketUrl}/ws?code=${code}&category=1`
        ) // category（类别）：1 H5（网页） 2 APP（移动端） 3 PC（桌面程序）
      }

      socket.onmessage = (message: MessageEvent<string>) => {
        if (message.data === 'pong') {
          return
        }

        const data: ISocketMessage = JSON.parse(message.data)

        if (data.code === 1) {
          // 存储本次 socket连接记录主键id
          if (!data.json || !data.json.socketId) {
            sessionStorage.setItem(SessionStorageKey.SOCKET_ID, '')
            console.error(new Error('系统故障：socketId为空'))
          } else {
            sessionStorage.setItem(
              SessionStorageKey.SOCKET_ID,
              data.json.socketId
            )
          }
          return resolve(null) // 得到 socketId之后，才调用 resolve()方法
        }

        if (data.code === 2 || data.code === 3 || data.code === 4) {
          // 2 账号已在其他地方登录，您被迫下线
          // 3 登录过期，请重新登录
          // 4 账号已被注销
          ToastError(data.codeDescription || 'Error：socket#onmessage', 5)
          logout()
          return
        }

        // 更新 redux里面 socket的值
        doSetSocketMessage({}) // 先重置，再设置值
        setTimeout(() => {
          doSetSocketMessage(data)
        }, 200)
      }
      socket.onopen = (event) => {
        console.log(`WebSocket连接 :>> ${socketUrl}`)
        doSetSocketStatus(true)
        heartbeat = setInterval(() => {
          // 每隔30秒钟发送一次心跳，避免socket连接因超时而自动断开
          socket?.send('ping')
        }, 30000)
        if (
          sessionStorage.getItem(SessionStorageKey.LOAD_MENU_FLAG) !== 'true'
        ) {
          getAppNav()('/') // 如果此时，还没有加载完菜单，则再加载一次
        }
      }
      socket.onclose = (event) => {
        console.log('WebSocket关闭')
        doSetSocketStatus(false)
        clearInterval(heartbeat) // 清除定时器
        if (!localStorage.getItem(LocalStorageKey.JWT)) {
          return // 如果没有 jwt，则不重连了，目的：防止一直连
        }
        setTimeout(() => {
          socket = null // 重置 socket对象，为了可以重新获取 socket连接地址
          connectionSocket(doSetSocketMessage, doSetSocketStatus)
        }, 2000) // 等待 2秒，再去重连socket
      }
    } else {
      ToastError('您的浏览器不支持WebSocket协议，请更换浏览器再试 (oﾟ▽ﾟ)o', 5)
    }
  })
}
